<?php
ini_set("display_errors", true);
error_reporting(E_ALL);

require_once('../simpletest/autorun.php');
require_once('../../src/v1/scottlib-test.php');

class TestCore extends UnitTestCase {

	private $conn;
	
	private $version;
	
	function setUp() {
		$this->conn = connect(array(
			'host' => ':/tmp/mysql.sock', //'localhost', 
			'user' => 'root', 
			'pass' => 'password', // '14allall41', 
			'db' => 'mysql'
		));
	}
	
	function tearDown() {
		disconnect();
	}
	
	function testConnnectWithMultipleArguments() {
		$this->assertNotNull(connect(':/tmp/mysql.sock', 'root', 'password', 'mysql'));
	}
	
	function testAssertHasLength() {
		$e = null;
		
		try {
			assert_has_length($e);	
		} catch (Exception $caught) {
			$e = $caught;
		}
		
		$this->assertNotNulL($e);
	}
	
	function testFuncParseArgs() {
		
		$hash = array('one' => 1, 'two' => 2, 'three' => 3);
		
		$index = array(1, 2, 3);
		
		$this->assertEqual(func_parse_args($hash, 'one', 0, true), 1);
		$this->assertEqual(func_parse_args($hash, 'two', 1, true), 2);
		$this->assertEqual(func_parse_args($hash, 'three', 2, true), 3);
		
		$e = null;
		try {
			func_parse_args($hash, 'foo', 3, true);
		} catch (Exception $caught) {
			$e = $caught;
		}
		$this->assertNotNull($e);
		
		$this->assertEqual(func_parse_args($index, 'one', 0, true), 1);
		$this->assertEqual(func_parse_args($index, 'two', 1, true), 2);
		$this->assertEqual(func_parse_args($index, 'three', 2, true), 3);
		
		$e = null;
		try {
			func_parse_args($index, 'foo', 3, true);
		} catch (Exception $caught) {
			$e = $caught;
		}
		$this->assertNotNull($e);
		
		$this->assertEqual(func_parse_args($hash, 'foo', 3, false, 'pass'), 'pass');
		$this->assertEqual(func_parse_args($index, 'foo', 3, false, 'pass'), 'pass');
		
	}
	
	function testNamespaceAvailabilityDetection() {
		// there is no framework and no extra libraries, so all core global functions should be available
		$this->assertTrue(function_exists('db'));
		$this->assertTrue(function_exists('query'));
		$this->assertTrue(function_exists('execute'));
		$this->assertTrue(function_exists('val'));
		$this->assertTrue(function_exists('begin'));
		$this->assertTrue(function_exists('begin_transaction'));
		$this->assertTrue(function_exists('rollback'));
		$this->assertTrue(function_exists('commit'));
	}
	
	function testDbFunction() {
		$this->assertEqual($this->conn, db());	
	}
	
	function testPreparedStatements() {
		// single parameter, no escaping
		$this->assertEqual('SELECT @@VERSION', prepare('SELECT %p', '@@VERSION'));
		
		// single parameter, escaping
		$this->assertEqual("SELECT * FROM `table` WHERE column='value'", prepare('SELECT * FROM `table` WHERE column=?', 'value'));
		
		// both
		$this->assertEqual("SELECT * FROM `table` WHERE column='value'", prepare('SELECT * FROM # WHERE column=?', 'table', 'value'));
		
		// single parameter, no escaping because numeric
		$this->assertEqual("SELECT 3.1415 4 0.0003 'value'", prepare('SELECT ? ? ? ?', 3.1415, 4, 0.0003, 'value'));
		
		// with new lines and tabs
		$this->assertEqual("
			SELECT *
			FROM `table`
			WHERE
				column = 'value'
		", prepare("
			SELECT *
			FROM #
			WHERE
				column = ?
		", 'table', 'value'));
		
		// named parameters
		$this->assertEqual(
			"SELECT * FROM `table` WHERE `column`='value1' OR `column`='value2'", 
			prepare("SELECT * FROM `table` WHERE `column`=:param1 OR `column`=:param2", array(
				'param1' => 'value1', 
				'param2' => 'value2'
			))
		);
		
		// named parameters with optional (null) replacement
		$this->assertEqual(
			"SELECT * FROM `table` WHERE `column`=null OR `column`='value2'", 
			prepare("SELECT * FROM `table` WHERE `column`=!:param1 OR `column`=:param2", array(
				'param2' => 'value2'
			))
		); 
		
		// named parameters and numeric parameter values
		$this->assertEqual(
			"SELECT * FROM `table` WHERE `column1`=3.1415 AND `column2`=4 AND `column3`=0.0003", 
			prepare("SELECT * FROM `table` WHERE `column1`=:param1 AND `column2`=:param2 AND `column3`=:param3", array(
				'param1' => 3.1415, 
				'param2' => 4, 
				'param3' => 0.0003
			))
		);
		
		// named parameters for system objects
		$this->assertEqual(
			"SELECT * FROM `foo` WHERE `bar`=1 OR `bar`='value'", 
			prepare("SELECT * FROM #table WHERE #column=:param1 OR #column=:param2", array(
				'table' => 'foo', 
				'column' => 'bar', 
				'param1' => 1, 
				'param2' => 'value'
			))
		);
		
		// calendar
		$this->assertEqual(
			"SELECT * FROM table WHERE date='1981/10/26 05:00:00'",
			prepare("SELECT * FROM table WHERE date=%c", '10/26/1981 5am')
		); 
		
		// numeric
		$this->assertEqual(
			"SELECT * FROM table WHERE number=3.1415 OR number=5",
			prepare("SELECT * FROM table WHERE number=%d OR number=%n", 
				3.1415,
				5
			)
		);
		
		// string
		$this->assertEqual(
			"SELECT * FROM table WHERE value='foo'",
			prepare("SELECT * FROM table WHERE value=%s", 'foo')
		);
		
	}
	
	function testSelectAsPrepare() {
		$record = query("
			SELECT
			? as `int`,
			? as `float`,
			? as `bool`,
			%c as `date`
		", 1, 3.1415, true, "Today")->first();
		
		$this->assertEqual($record->int, 1);
		$this->assertEqual($record->float, 3.1415);
		$this->assertEqual($record->bool, true);
		$this->assertEqual(strtotime($record->date), strtotime('Today'));
		
		$record = query("
			SELECT
			:int as `int`,
			:float as `float`,
			:bool as `bool`,
			:date as `date`
		", array(
		'int' => 1, 
		'float' => 3.1415, 
		'bool' => true, 
		'date' => strtotime("Today")
		))->first();
		
		$this->assertEqual($record->int, 1);
		$this->assertEqual($record->float, 3.1415);
		$this->assertEqual($record->bool, true);
		$this->assertEqual($record->date, strtotime('Today'));
	}
	
	function testBasicQuerying() {
		$this->version = val('SELECT @@VERSION');
		$this->assertTrue(strlen($this->version));
	
		$rs = query('SELECT @@VERSION as `version`');
		$this->assertTrue($rs->count() === 1);
		$this->assertTrue($rs->fieldCount() === 1);
		
		foreach($rs->objects() as $i => $value) {
			$this->assertEqual($this->version, $value->version);
		}
		
		$this->assertEqual($i, 0);
		$i = null;
		
		foreach($rs->hashes() as $i => $value) {
			$this->assertEqual($this->version, $value['version']);
		}
		$this->assertEqual($i, 0);
		$i = null;
		
		foreach($rs->arrays() as $i => $value) {
			$this->assertEqual($this->version, $value[0]);
		}
		$this->assertEqual($i, 0);
		$i = null;	
	}
	
}